﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NetworkingLibrary.Messages.Java
{
    [Serializable]
    public class JavaMessageObject : MessageObject
    {
        public Dictionary<string, JavaDataObject> AllObjects;

        public JavaMessageObject(Dictionary<string, JavaDataObject> SomeData)
            : base()
        {
            AllObjects = SomeData;
        }
        public JavaMessageObject(byte[] SomeData)
        {
            FromBytes(SomeData);
        }

        public byte[] ToBytes()
        {
            Dictionary<string, byte[]> DataBytes = new Dictionary<string, byte[]>(AllObjects.Count * 10);
            foreach (KeyValuePair<string, JavaDataObject> AnObj in AllObjects)
            {
                DataBytes.Add(AnObj.Key, JavaDataObjectHandler.ToBytes(AnObj.Value));
            }
            int MaxObjLength = 0;
            int MaxKeyLength = 0;
            DataBytes.ToList().ForEach(delegate(KeyValuePair<string, byte[]> Data)
            {
                if (Data.Value.Length > MaxObjLength)
                {
                    MaxObjLength = Data.Value.Length;
                }
                if (System.Text.Encoding.UTF8.GetBytes(Data.Key).Length > MaxKeyLength)
                {
                    MaxKeyLength = Data.Key.Length;
                }
            });

            MaxKeyLength += 1;
            MaxObjLength += 1;

            List<byte> ReturnData = new List<byte>();
            ReturnData.AddRange(BitConverter.GetBytes(MaxKeyLength));
            ReturnData.AddRange(BitConverter.GetBytes(MaxObjLength));

            foreach (KeyValuePair<string, byte[]> SomeData in DataBytes)
            {
                List<byte> KeyData = System.Text.Encoding.UTF8.GetBytes(SomeData.Key).ToList();
                KeyData.Insert(0, 1);
                for (int i = KeyData.Count; i < MaxKeyLength; i = KeyData.Count)
                {
                    KeyData.Insert(0, 0);
                }

                List<byte> ObjData = SomeData.Value.ToList();
                ObjData.Insert(0, 1);
                for (int i = ObjData.Count; i < MaxObjLength; i = ObjData.Count)
                {
                    KeyData.Insert(0, 0);
                }

                ReturnData.AddRange(KeyData);
                ReturnData.AddRange(ObjData);
            }

            int Length = ReturnData.Count + 4;
            byte[] LengthBytes = BitConverter.GetBytes(Length);
            for (int i = LengthBytes.Length - 1; i > -1; i--)
            {
                ReturnData.Insert(0, LengthBytes[i]);
            }
            return ReturnData.ToArray();
        }
        public void FromBytes(byte[] Data)
        {
            List<byte> data = Data.ToList();

            int KeyLength = BitConverter.ToInt32(data.Take(4).ToArray(), 0);
            data.RemoveRange(0, 4);
            int ObjLength = BitConverter.ToInt32(data.Take(4).ToArray(), 0);
            data.RemoveRange(0, 4);

            AllObjects = new Dictionary<string, JavaDataObject>(Data.Length / 10);

            while(data.Count >= (KeyLength + ObjLength))
            {
                List<byte> BlockBytes = data.Take(KeyLength + ObjLength).ToList();
                data.RemoveRange(0, KeyLength + ObjLength);

                List<byte> KeyBytes = new List<byte>(KeyLength);
                bool Adding = false;
                for (int ByteNum = 0; ByteNum < KeyLength; ByteNum++)
                {
                    if (Adding)
                    {
                        KeyBytes.Add(BlockBytes[ByteNum]);
                    }
                    Adding = Adding || BlockBytes[ByteNum] == 1;
                }
                if (KeyBytes.Count == 0)
                {
                    break;
                }
                string Key = System.Text.Encoding.UTF8.GetString(KeyBytes.ToArray());
                BlockBytes.RemoveRange(0, KeyLength);

                List<byte> ObjBytes = new List<byte>(ObjLength);
                Adding = false;
                for (int ByteNum = 0; ByteNum < ObjLength; ByteNum++)
                {
                    if (Adding)
                    {
                        ObjBytes.Add(BlockBytes[ByteNum]);
                    }
                    Adding = Adding || BlockBytes[ByteNum] == 1;
                }
                JavaDataObject Obj = JavaDataObjectHandler.FromBytes(ObjBytes.ToArray());

                AllObjects.Add(Key, Obj);
            }
        }
    }
}
